package com.xgs.common.utils.sign;

import com.xgs.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Md5加密方法
 * 
 * @author xgs
 */
public class Md5Utils
{
    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);

    private static byte[] md5(String s)
    {
        MessageDigest algorithm;
        try
        {
            algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(s.getBytes("UTF-8"));
            byte[] messageDigest = algorithm.digest();
            return messageDigest;
        }
        catch (Exception e)
        {
            log.error("MD5 Error...", e);
        }
        return null;
    }

    private static final String toHex(byte hash[])
    {
        if (hash == null)
        {
            return null;
        }
        StringBuffer buf = new StringBuffer(hash.length * 2);
        int i;

        for (i = 0; i < hash.length; i++)
        {
            if ((hash[i] & 0xff) < 0x10)
            {
                buf.append("0");
            }
            buf.append(Long.toString(hash[i] & 0xff, 16));
        }
        return buf.toString();
    }

    public static String hash(String s)
    {
        try
        {
            return new String(toHex(md5(s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
        }
        catch (Exception e)
        {
            log.error("not supported charset...{}", e);
            return s;
        }
    }

    /**
     * xgs带中文加密算法
     *
     * @param Src      需要加密的字符串
     * @param Encrypt  True为加密，False为解密
     * @param zKey     种子
     * @param baseFlag True为使用base64加密，False为不使用
     * @return
     */
    public static String EncryptEx(String Src, Boolean Encrypt, String zKey, Boolean baseFlag) {
        String strEnc = "UTF-8";

        if (StringUtils.isEmpty(Src)) {
            return "";
        }

        int KeyLen, KeyPos, offset, SrcPos, SrcAsc, TmpSrcAsc, Range, hexTemp;
        KeyLen = zKey.length();
        if (KeyLen == 0) {
            zKey = "Hello";
        }
        KeyPos = 0;
        Range = 256;
        if (Encrypt) {
            try {
                if (baseFlag) {
                    //Base64编码
                    Src = Base64.encode(Src.getBytes(strEnc));
                }
                String Desc = "";
                String sTemp = "";
                Random rd = new Random(Range);
                offset = rd.nextInt(255);
                Desc = String.format("%02x", offset);

                byte[] chrSrc = new byte[0];
                byte[] bytezKey;
                char[] chrzKey = new char[0];
                try {
                    chrSrc = Src.getBytes(Charset.forName(strEnc));
                    bytezKey = zKey.getBytes(Charset.forName(strEnc));
                    chrzKey = new String(bytezKey, Charset.forName(strEnc)).toCharArray();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                for (SrcPos = 1; SrcPos <= chrSrc.length; SrcPos++) {
                    SrcAsc = (chrSrc[SrcPos - 1] + offset) % 255;
                    SrcAsc = SrcAsc ^ chrzKey[KeyPos];
                    if (KeyPos < KeyLen - 1) {
                        KeyPos++;
                    } else {
                        KeyPos = 0;
                    }
                    Desc += String.format("%02x", SrcAsc);
                    offset = SrcAsc;
                }


                sTemp = "";
                for (SrcPos = 1; SrcPos <= Desc.length() / 2; SrcPos++) {
                    sTemp = sTemp + Desc.charAt(Desc.length() - (SrcPos)) + Desc.charAt(SrcPos - 1);
                }

                hexTemp = 0;
                for (SrcPos = 0; SrcPos <= sTemp.length() / 2 - 1; SrcPos++) {
                    hexTemp = hexTemp ^ Integer.parseInt(sTemp.substring(SrcPos * 2, SrcPos * 2 + 2), 16);
                }

                sTemp = String.format("%02x", hexTemp) + sTemp;

                Desc = sTemp.toUpperCase();
                return Desc;
            } catch (Exception e) {
                //e.printStackTrace();
                log.error("解码异常：" + e);
                throw new RuntimeException("加密异常");
            }
        } else {
            try {
                List<Byte> listDesc = new ArrayList<>();
                //listDesc.clear();

                hexTemp = 0;
                for (SrcPos = 0; SrcPos < Src.length() / 2 - 1; SrcPos++) {
                    hexTemp = hexTemp ^ Integer.parseInt(Src.substring(SrcPos * 2 + 2, SrcPos * 2 + 2 + 2), 16);
                }

                if (!(Src.substring(0, 2)).equalsIgnoreCase(String.format("%02x", hexTemp))) {
                    return "";
                }

                String sTemp = "";
                for (SrcPos = Src.length() / 2 - 1; SrcPos >= 1; SrcPos--) {
                    sTemp = Src.substring(SrcPos * 2 + 1, SrcPos * 2 + 1 + 1) + sTemp + Src.charAt(SrcPos * 2);
                }

                offset = Integer.parseInt(sTemp.substring(0, 2), 16);

                byte[] bytezKey;
                char[] chrzKey = new char[0];
                try {
                    bytezKey = zKey.getBytes(Charset.forName(strEnc));
                    chrzKey = new String(bytezKey, Charset.forName(strEnc)).toCharArray();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                SrcPos = 2;
                do {
                    SrcAsc = Integer.parseInt(sTemp.substring(SrcPos, SrcPos + 2), 16);
                    TmpSrcAsc = SrcAsc ^ chrzKey[KeyPos];
                    if (KeyPos < KeyLen - 1) {
                        KeyPos++;
                    } else {
                        KeyPos = 0;
                    }
                    if (TmpSrcAsc <= offset) {
                        TmpSrcAsc = 255 + TmpSrcAsc - offset;
                    } else {
                        TmpSrcAsc = TmpSrcAsc - offset;
                    }
                    listDesc.add((byte) TmpSrcAsc);
                    offset = SrcAsc;
                    SrcPos = SrcPos + 2;
                } while (SrcPos < sTemp.length());


                byte[] byteArrDesc = new byte[listDesc.size()]; // 将 List 转换为 byte 数组
                for (int i = 0; i < listDesc.size(); i++) {
                    byteArrDesc[i] = listDesc.get(i);
                }

                String strDesc = new String(byteArrDesc, Charset.forName(strEnc));

                if (baseFlag) {
                    //Base64解码
                    strDesc = new String(Base64.decode(strDesc), Charset.forName(strEnc));
                }

                return strDesc;
            } catch (Exception e) {
                log.error("解码异常：" + e);
                throw new RuntimeException("解码异常");
            }
        }
    }
}
